#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h> 
//irq head
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>


//确定主设备号
static int major  = 0;
static struct class *gpio_drv_class;
static struct gpio_desc *gpio_drv_des;
static int gpio_key_irq ;
static int gpio;

/*实现环形队列*/
#define buffer_len  128
static int  circle_buff[buffer_len];
int r ,w;

#define NEXT_POS(x) ((x+1)%buffer_len)

static int buffer_is_empty(void)
{
	return (r == w);
}


static int buffer_is_full(void)
{
	return (r == NEXT_POS(w));
}

static void buffer_data_push(int val)
{
	if(!buffer_is_full())
	{
		circle_buff[w]  = val;
		w = NEXT_POS(w);
	}
}
 
static int buffer_date_pull(void)
{
	int ret =0;
	if(!buffer_is_empty())
	{
		ret = circle_buff[r];
		r = NEXT_POS(r);
	} 
	return ret;
}

//初始化等待wq队列
static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);

/* 3. 实现对应的open/read/write等函数，填入file_operations结构体                   */
static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	int key;
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	wait_event_interruptible(gpio_key_wait,!buffer_is_empty());
	key = buffer_date_pull();
	err = copy_to_user(buf,&key,sizeof(key));
	return 4;
}

/* write(fd, &val, 1); */
static ssize_t gpio_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	char status;
	
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(&status, buf, 1);

	/* 根据次设备号和status控制LED */
	 //gpiod_set_value(gpio_drv_des, status);
	
	gpio_direction_output(gpio,status);
	return 1;
}

static int gpio_drv_open (struct inode *node, struct file *file)
{
	//int minor = iminor(node);
	
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	/* 根据次设备号初始化LED */
	//gpiod_direction_output(gpio_drv_des, 0);
	
	return 0;
}

static int gpio_drv_close (struct inode *node, struct file *file)
{
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

#if 0
int (*fasync) (int, struct file *, int);
struct fasync_struct {
	spinlock_t		fa_lock;
	int			magic;
	int			fa_fd;
	struct fasync_struct	*fa_next; /* singly linked list */
	struct file		*fa_file;
	struct rcu_head		fa_rcu;
};

fasync_helper(fd,file,start,&gpio_sync)
① 驱动文件的 flag 被设置为 FAYNC 时：
button_async->fa_file = filp; // filp 表示驱动程序文件，里面含有之前设置的 PID
② 驱动文件被设置为非 FASYNC 时：
button_async->fa_file = NULL;

#endif


static struct fasync_struct *gpio_sync;

static int gpio_drv_fsync (int fd, struct file *file, int start)
{
	printk(KERN_INFO"set gpio_drv_fsync\n");
	return fasync_helper(fd,file,start,&gpio_sync);
}
static struct file_operations gpio_drv = {
	.owner	 = THIS_MODULE,
	.open    = gpio_drv_open,
	.read    = gpio_drv_read,
	.write   = gpio_drv_write,
	.release = gpio_drv_close,
	.fasync   = gpio_drv_fsync,
};

static irqreturn_t gpio_key_irq_func(int irq,void * pfile)
{
	static int  irq_count =0;
	int key = 0;
	irq_count++;
	
	key  =  gpio_get_value(gpio);
	buffer_data_push(key);
	// printk(KERN_INFO"key %s  %d\n","power_key",irq_count);
	wake_up_interruptible(&gpio_key_wait);//唤醒read 
	kill_fasync(&gpio_sync,SIGIO,POLL_IN);
	return IRQ_HANDLED;
}
//从设备树 中的 节点中获取资源    获得 gpio_drv 中的数据
//将file_operation 结构体提交到内核 注册驱动程序
static int gpio_drv_probe(struct platform_device *pdev)
{

	enum of_gpio_flags flag; 
	struct device_node *rk_led_node = pdev->dev.of_node;
	const char* dedefault_state ;
	int erro ;

    printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	gpio = of_get_named_gpio_flags(rk_led_node, "gpios", 0, &flag);
	of_property_read_string(rk_led_node,"dedefault-state",&dedefault_state);//从设备树中获取指定的  字符串
	/* >0 有效   ； <0 无效 */
	if (!gpio_is_valid(gpio))
	{	
		printk(KERN_INFO "cat not find gpio \n");
		return -ENODEV;
	}
	
	/* 申请GPIO */
	gpio_request(gpio, "gpios");

	//获得中断号
	gpio_key_irq = gpio_to_irq(gpio);
	//注册中断
	erro =  request_irq(gpio_key_irq,gpio_key_irq_func,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,"gpio_key_irq",(void *)1);
	if(erro)
	{
		free_irq(gpio_key_irq,(void *)1); //释放中断
		printk(KERN_INFO  "free_irq\n");
	}
	//printk(KERN_INFO "gpio num is %d  of_gpio_flags  = %d  dedefault_state = %s\n", gpio,flag,gpio_key_irq);		

    //注册file_operation 结构体
    major = register_chrdev(major,"my_gpio_drv",&gpio_drv);

	//创建  gpio_drv 类
	gpio_drv_class = class_create(THIS_MODULE,"my_gpio_class");
	//判断是创建成功 
	if(IS_ERR(gpio_drv_class))
	{
		 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		 unregister_chrdev(major,"my_gpio_drv");
		 gpiod_put(gpio_drv_des);//释放gpio
		 return PTR_ERR(gpio_drv_class);
	}

	device_create(gpio_drv_class,NULL,MKDEV(major, 0),NULL,"my_gpio_drv%d",0);//创建设备
	return  0;

}

static int gpio_drv_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    device_destroy(gpio_drv_class, MKDEV(major, 0));
	class_destroy(gpio_drv_class);
	unregister_chrdev(major, "my_gpio_drv");
	gpio_free(gpio);
    free_irq(gpio_key_irq,(void *)1);
    return 0;
}



static struct of_device_id gpios[] = 
{
    {.compatible = "firefly,gpio-key"},
    {},
};

//定义 platform_driver
static  struct platform_driver gpio_drv_platform_driver =
{
    .probe = gpio_drv_probe,
    .remove = gpio_drv_remove,
    .driver =
    {
        .name = "gpio_drv",
        .of_match_table = gpios,
    },

};


//注册平台设备
static int __init gpio_drv_init(void)
{
	int err;
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = platform_driver_register(&gpio_drv_platform_driver);
	return  err;
}

//卸载平台设备 ， 在设备卸载的时候调用
static void gpio_drv_exit(void)
{
	printk(KERN_INFO "%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	platform_driver_unregister(&gpio_drv_platform_driver);
}


//使用内核宏 将设备告诉内核
module_init(gpio_drv_init);
module_exit(gpio_drv_exit);
MODULE_LICENSE("GPL");
